package _2_函数_运算;

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import org.openjdk.jol.vm.VM;

/**
 * <pre>
 * 函数调用时, 参数传递是 变量中保存的值
 *
 * 深度clone
 * 1. 实现 Cloneable接口,重写clone方法
 * 2. 使用手工代码 new Object, 然后set(get()) 方法
 *    2.1 使用 MapStruct 简化代码
 * 3. 使用序列化
 * </pre>
 */
@SuppressWarnings({"all"})
public class _1_参数传递 implements Cloneable {

  // 引用类型, 使用 = 赋值到新变量,
  @Test
  public void 等号赋值传递的是什么() {
    List<String> old = Lists.newArrayList("0", "1", "2", "3", "4");
    List<String> newList = old;   // old 和 newList 传递的是引用地址, 新旧两个变量指向同一个对象
    newList.set(0, "new_0");      // 改变新变量的值,
    // 使用 org.openjdk.jol:jol-core 打印对象在内存中的地址
    System.out.println(VM.current().addressOf(old) + ": " + old);
    System.out.println(VM.current().addressOf(newList) + ": " + newList);

    // 使用 new 关键字创建了新对象, newList 引用不再指向老对象，老对象是不改变
    newList = Lists.newArrayList("1");
    System.out.println(VM.current().addressOf(newList) + ": " + newList);
  }

  /**
   * 函数调用时, 传递的是 值, 引用类型传递的也是值 (对象的地址)
   */
  public static void main(String[] args) {
    int a = 1;
    addInt(a);
    System.out.println("执行addInt函数 后, a的值:\t\t" + a);

    List<String> old = Lists.newArrayList("1", "2");
    changeList(old);  // ★★★★★ 可以把函数拆解为如下，传入的参数是一个复制的"指针"
                      // List<String> args = old;    args = List.of("3", "4")
    System.out.println("changeList函数没有改变old的值:" + old);
  }

  private static void changeList(List<String> old) {
    old = Lists.newArrayList("3", "4");
    System.out.println("changeList函数 中, 参数值改为:\t"+ old);
  }

  private static void addInt(int b) {
    b = b + 1;
    System.out.println("执行addInt函数 中, 参数值为: \t" + b);
  }

  // 深浅复制--引用传递--值传递
  @Test
  public void useDeepCopy() {
    List<String> old = Lists.newArrayList("0", "1", "2", "3", "4");

    // 使用 = 给新变量 使用构造器重新创建
    List<String> list = new ArrayList<>(old);
    // 改变新变量的值
    list.set(0, "new_0");
    // 旧的变量不会改变
    System.out.println(VM.current().addressOf(old) + ": " + old);
    System.out.println(VM.current().addressOf(list) + ": " + list);
  }
}
